#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#include "jpeglib.h"
#include "main.h"

int read_jpeg_file(const char *filename, ImageInfo *imageinfo_buf){
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE *fp;
    JSAMPARRAY buffer;
    int row_width;
    
    cinfo.err = jpeg_std_error(&jerr);  
    
    fp = fopen(filename, "rb");
    if(fp == NULL){
        perror("fopen");
        return -1;
    }
    
    jpeg_create_decompress(&cinfo);
    
    jpeg_stdio_src(&cinfo, fp);
    
    jpeg_read_header(&cinfo, TRUE);
    
    cinfo.out_color_space = JCS_GRAYSCALE;
    
    jpeg_start_decompress(&cinfo);
    
    row_width = cinfo.output_width * cinfo.output_components;
    
    buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_width, 1);
    
    unsigned char *output_buffer;
    
    output_buffer = (unsigned char *)malloc(row_width * cinfo.output_height);
    memset(output_buffer, 0, row_width * cinfo.output_height);
    unsigned char *tmp = output_buffer;
    
    while (cinfo.output_scanline < cinfo.output_height){
        jpeg_read_scanlines(&cinfo, buffer, 1);
        memcpy(tmp, *buffer, row_width);
        tmp += row_width;
    }
    
    
    jpeg_finish_decompress(&cinfo);
    
    jpeg_destroy_decompress(&cinfo);
    
    fclose(fp);
    
    imageinfo_buf->src = output_buffer;
    imageinfo_buf->height = cinfo.output_height;
    imageinfo_buf->width = cinfo.output_width;
    
    return 0;
}

int binaryzation(ImageInfo *imageinfo){
    unsigned char *img = imageinfo->src;

    int i,j;
    for(i=0;i<imageinfo->height;i++){
        for(j=0;j<imageinfo->width;j++){
            if(img[imageinfo->width*i + j]>150){
                img[imageinfo->width*i + j] = 0;
            }else{
                img[imageinfo->width*i + j] = 1;
            }
        }
    }
    
    return 0;
}

int segmentation(ImageInfo *imageinfo){
    unsigned char *img = imageinfo->src;
    int i,j,x,y,k;
    
    unsigned char *w = malloc(imageinfo->width);
    memset(w, 0, imageinfo->width);
    
    unsigned char *h = malloc(imageinfo->height);
    memset(h, 0, imageinfo->height);
    
    for(i=0;i<imageinfo->height;i++){
        for(j=0;j<imageinfo->width;j++){
            w[j] += img[imageinfo->width*i + j];
            w[j] = min(w[j], 9);
            h[i] += img[imageinfo->width*i + j];
            h[i] = min(h[i], 9);
        }
    }
    
    unsigned char *n = malloc(imageinfo->width * imageinfo->height * N_COUNT);
    memset(n, 0, imageinfo->width * imageinfo->height * N_COUNT);
    x=0;
    for(j=0,y=0,k=0;j<imageinfo->width;j++){
        if(w[j] > 0){
            for(i=0,x=0;i<imageinfo->height;i++){
                if(h[i] > 1){
                    n[imageinfo->width * imageinfo->height*k + imageinfo->width*x + y] = img[imageinfo->width*i + j];
                    x++;
                }
            }
            y++;
            if(w[j+1] == 0){
                k++;
                y=0;
            }
        }
    }
    
    imageinfo->src = n;

    free(w);
    free(h);
    return 0;
}

int display(ImageInfo *imageinfo){
    unsigned char *img = imageinfo->src;
    int i,j;
    
    for(i=0;i<imageinfo->height;i++){
        for(j=0;j<imageinfo->width;j++){
            if(img[imageinfo->width*i + j] > 0){
                printf("O");
            }else{
                printf(" ");
            };
        }
        printf("\n");
    }
    //printf("\nwidth=%d height=%d\n", imageinfo->width, imageinfo->height);
}

int predict(unsigned char *buf, unsigned char *img){
    int goal[IMG_COUNT];
    int i,j,k;
    int max = 0, max_num = 0;
    memset(goal, 0, sizeof(goal));
    for(k=0;k<IMG_COUNT;k++){
        for(i=0;i<IMG_XSIZE;i++){
            for(j=0;j<IMG_YSIZE;j++){
                if(buf[IMG_XSIZE*IMG_YSIZE*k + IMG_YSIZE*i + j] == img[IMG_XSIZE*i + j]){
                    goal[k]++;
                }
            }
        }
        if(goal[k] >= max){
            max_num = k;
            max = goal[k];
        }
    }
    
    return max_num;
}

int extract(ImageInfo *imageinfo){
    unsigned char *n = imageinfo->src;
    int i,j,k,t;
    FILE *fp;
    
    for(k=0;k<N_COUNT;k++){
        int x1,y1;
        unsigned char *tbuf = malloc(IMG_XSIZE*IMG_YSIZE);
        for(x1=0;x1<IMG_XSIZE;x1++){
            for(y1=0;y1<IMG_YSIZE;y1++){
                tbuf[IMG_XSIZE*x1 + y1] = n[imageinfo->width * imageinfo->height*k + imageinfo->width*x1 + y1];
            }
        }
        int right = predict(model, tbuf);
        printf("%d", right);
    }
    printf("\n");
    return 0;
}

int train(ImageInfo *imageinfo){
    unsigned char *n = imageinfo->src;
    int i,j,k,t;
    FILE *fp;
    
    fp = fopen(DATA_FILE, "rb");
    if(fp == NULL){
        perror("fopen");
        return -1;
    }
    
    unsigned char *buf = malloc(IMG_XSIZE*IMG_YSIZE*IMG_COUNT);
    int ret = fread(buf, 1, IMG_XSIZE*IMG_YSIZE*IMG_COUNT, fp);
    printf("read file %d\n", ret);
    fclose(fp);
    
    for(k=0;k<N_COUNT;k++){
        for(i=0;i<imageinfo->height-6;i++){
            for(j=0;j<imageinfo->width;j++){
                if(n[imageinfo->width * imageinfo->height*k + imageinfo->width*i + j] > 0){
                    printf("*");
                }else{
                    printf(" ");
                };
            }
            printf("\n");
        }
        int x1,y1;
        unsigned char *tbuf = malloc(IMG_XSIZE*IMG_YSIZE);
        for(x1=0;x1<IMG_XSIZE;x1++){
            for(y1=0;y1<IMG_YSIZE;y1++){
                tbuf[IMG_XSIZE*x1 + y1] = n[imageinfo->width * imageinfo->height*k + imageinfo->width*x1 + y1];
            }
        }
        int right = predict(buf, tbuf);
        printf("System guess number :%d\nInput a number:", right);
        scanf(" %d", &t);
        for(x1=0;x1<IMG_XSIZE;x1++){
            for(y1=0;y1<IMG_YSIZE;y1++){
                buf[IMG_XSIZE*IMG_YSIZE*t + IMG_YSIZE*x1 + y1] = n[imageinfo->width * imageinfo->height*k + imageinfo->width*x1 + y1];
            }
        }
    }
    
    fp = fopen(DATA_FILE, "wb");
    if(fp == NULL){
        perror("fopen");
        return -1;
    }
    
    ret = fwrite(buf, 1, IMG_XSIZE*IMG_YSIZE*IMG_COUNT, fp);
    printf("write file %d\n", ret);
    
    fclose(fp);
    return 0;
}

int usage(const char *progname)
{
	fprintf(stderr, "Test1: SVM\n\n"
			"Usage: %s <options>\n"
			"\n"
			"Options:\n"
			"\t-t <train>\n"
			"\t-p <predict>\n"
			"\t-i <image>\n"
			"\n",
		progname);
	return(-1);
}

int main(int argc, char *argv[]){
    int ch;
    char *img_name;
    ImageInfo imageinfo;
    
    int choose = 0;
    
    if(argc == 1){
        usage(argv[0]);
        return -1;
    }
    
    while ((ch = getopt(argc, argv, "tpi:")) != -1) {
		switch(ch) {
			case 't':
				choose = 1;
				break;
			case 'p':
                choose = 2;
				break;
            case 'i':
                img_name = optarg;
				break;
			default:
				usage(argv[0]);
				return -1;
		}
	}
    
    if(choose == 0){
        read_jpeg_file(img_name, &imageinfo);
        binaryzation(&imageinfo);
        display(&imageinfo);
    }
    
    if(choose == 1){
        read_jpeg_file(img_name, &imageinfo);
        binaryzation(&imageinfo);
        train(&imageinfo);
    }
    
    if(choose == 2){
        read_jpeg_file(img_name, &imageinfo);
        binaryzation(&imageinfo);
        segmentation(&imageinfo);
        extract(&imageinfo);
    }
    
    free(imageinfo.src);
    return 0;
}